/*
 *  Copyright 2010 mazhao.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package shopping.front;

import com.octo.captcha.service.CaptchaServiceException;
import com.opensymphony.xwork2.ModelDriven;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import shopping.commons.BaseAction;
import shopping.commons.CaptchaServiceSingleton;
import shopping.commons.Digester;
import shopping.commons.Util;
import shopping.model.LoginInfo;
import shopping.model.Province;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

/**
 * @author mazhao
 */
public class CustomerAction extends BaseAction implements ModelDriven<LoginInfo> {

    private Log log = LogFactory.getLog(this.getClass());

    // ============================================
    // -- model object--
    // ============================================
    private LoginInfo loginInfo = new LoginInfo();

    // ============================================
    // -- action method --
    // ============================================

    private List<Province> provinces = new ArrayList<Province>();

    public List<Province> getProvinces() {
        return provinces;
    }

    /**
     * prepare for login.jsp(login or register)
     *
     * @return
     */
    @Action(value = "/front/login",
            results = {
                    @Result(name = "success", location = "/WEB-INF/content/front/login.jsp")
            })
    public String login() {
        log.debug("enter front/login action");

        // initialize province list
        this.provinces = Province.getAll();

        return SUCCESS;
    }

    /**
     * login in
     *
     * @return
     */
    @Action(value = "/front/enter",
            results = {
                    @Result(name = "success", location = "/", type = "redirect"),
                    @Result(name = "input", location = "/WEB-INF/content/front/login.jsp")
            })
    public String enter() {
        if (checkJcaptha() && checkUserLoginInfo()) {
            log.debug("login user:" + getModel());
            //ActionContext.getContext().getSession().put(LoginInfo.SK_LOGIN_INFO, loginInfo);
            Util.Security.saveUserToSession(loginInfo);
            return SUCCESS;
        } else {
            log.debug("login failed, add error message:" + getText("login.failed"));
            addActionError(getText("login.failed"));
            return INPUT;
        }
    }

    /**
     * logout
     *
     * @return
     */
    @Action(value = "/front/exit",
            results = {
                    @Result(name = "success", location = "/", type = "redirect")
            }
    )
    public String exit() {
        //ActionContext.getContext().getSession().remove(LoginInfo.SK_LOGIN_INFO);
        Util.Security.removeUserFromSession();
        return SUCCESS;
    }


    /**
     * register new customer.
     *
     * @return success for success, input else
     */
    @Action(value = "/front/create",
            results = {
                    @Result(name = "success", location = "/", type = "redirect"),
                    @Result(name = "input", location = "/WEB-INF/content/front/login.jsp", type = "dispatcher", params = {"type", "register"})
            })
    public String create() {
        if (checkUserLoginInfoExist()) {
            log.debug("create failed for " + getText("create.userexist"));
            addActionError(getText("create.userexist"));
            HttpServletRequest request = ServletActionContext.getRequest();
            request.setAttribute("type", "register");

            return INPUT;
        } else {
            createUserLoginInfo();
            return SUCCESS;
        }
    }
    // ============================================
    // -- logic method --
    // ============================================

    /**
     * check user password
     * @return true if user exists and password equals, false else.
     */
    protected boolean checkUserLoginInfo() {

        LoginInfo info = new LoginInfo();
        info.setUsername(getModel().getUsername());

        if (info.load() && info.getPassword().equals(Digester.crypt(getModel().getPassword())) && info.isStatus()) {
            // add role id and role
            this.loginInfo = info;
            return true;
        } else {
            return false;
        }
    }

    /**
     * check if human beings
     * @return
     */
    private boolean checkJcaptha() {
        String jcaptha = getModel().getJcaptcha();
        boolean ret = false;

        try {
            String sessionId = ServletActionContext.getRequest().getSession().getId();
            ret = CaptchaServiceSingleton.getInstance().validateResponseForID(sessionId, jcaptha);
        } catch (CaptchaServiceException e) {
            e.printStackTrace();
        }

        return ret;
    }

    /**
     * check if user exist.
     * @return
     */
    private boolean checkUserLoginInfoExist() {
        LoginInfo info = new LoginInfo();
        info.setUsername(getModel().getUsername());
        return info.load();
    }

    /**
     * create new user(with crypt password)
     */
    private void createUserLoginInfo() {
        getModel().setPassword(Digester.crypt(getModel().getPassword()));
        getModel().register();
    }

    // ======================================================
    // -- method for ModelDriven interface --
    // ======================================================

    @Override
    public LoginInfo getModel() {
        return loginInfo;
    }
}
